#include <57header.h>

// 设置文件类型和权限字符串
void set_type_mode(mode_t mode, char* mode_str) {
    // 根据文件类型设置字符串的第一个字符
    switch (mode & S_IFMT) {
    case S_IFBLK:  mode_str[0] = 'b'; break; // 块设备
    case S_IFCHR:  mode_str[0] = 'c'; break; // 字符设备
    case S_IFDIR:  mode_str[0] = 'd'; break; // 目录
    case S_IFIFO:  mode_str[0] = 'p'; break; // 管道
    case S_IFLNK:  mode_str[0] = 'l'; break; // 链接
    case S_IFREG:  mode_str[0] = '-'; break; // 常规文件
    case S_IFSOCK: mode_str[0] = 's'; break; // 套接字
    default:       mode_str[0] = '?'; break; // 未知类型
    }

    // 根据文件权限设置字符串后续字符
    // 设置拥有者权限
    mode_str[1] = (mode & 0400) ? 'r' : '-';
    mode_str[2] = (mode & 0200) ? 'w' : '-';
    mode_str[3] = (mode & 0100) ? 'x' : '-';
    // 设置拥有者组的权限
    mode_str[4] = (mode & 0040) ? 'r' : '-';
    mode_str[5] = (mode & 0020) ? 'w' : '-';
    mode_str[6] = (mode & 0010) ? 'x' : '-';
    // 设置其他人的权限
    mode_str[7] = (mode & 0004) ? 'r' : '-';
    mode_str[8] = (mode & 0002) ? 'w' : '-';
    mode_str[9] = (mode & 0001) ? 'x' : '-';
    mode_str[10] = '\0'; // 确保字符串以 null 结尾
}

// 获取格式化的时间字符串
void get_time_str(time_t mtime, char* time_str) {
    // 月份的缩写的字符二维数组（字符串数组）
    char mon_arr[][10] = {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    struct tm* tm_val = localtime(&mtime);		// 获取tm结构体指针
    sprintf(time_str, 
            "%s %02d %02d:%02d", 
            mon_arr[tm_val->tm_mon],	// 月份
            tm_val->tm_mday,	// 天数
            tm_val->tm_hour,	// 时
            tm_val->tm_min);	// 分
}

/* Usage: ./07_myls pathname 或 ./07_myls */
int main(int argc, char* argv[]) {
    char* dir_name; // 存储目录名的指针
    if(argc == 1) {
        dir_name = ".";  // 如果命令行参数没有提供要打印的目录，就打印当前工作目录
    }
    else if (argc == 2){
        dir_name = argv[1]; // 否则使用提供的命令行参数作为待打印的目标
    }else {
        fprintf(stderr, "args num error!\n");
        exit(1);
    }

    DIR* dirp = opendir(dir_name); // 打开指定的目录
    ERROR_CHECK(dirp, NULL, "opendir");

    // 改变工作目录到指定目录
    int ret = chdir(dir_name);
    ERROR_CHECK(ret, -1, "chdir");

    struct dirent* pdirent;
    // 遍历目录项
    while ((pdirent = readdir(dirp)) != NULL) {
        struct stat stat_buf;
        // 获取目录项的详细信息
        int ret = stat(pdirent->d_name, &stat_buf);
        ERROR_CHECK(ret, -1, "stat");

        char mode_str[1024] = { 0 }; // 保存文件类型和权限信息
        set_type_mode(stat_buf.st_mode, mode_str); // 设置类型和权限

        char time_str[1024] = { 0 }; // 保存格式化后的时间信息
        get_time_str(stat_buf.st_mtime, time_str); // 获取时间字符串

        printf("%s %lu %s %s %4lu %s %s\n", 
               mode_str,							// 文件类型与权限
               stat_buf.st_nlink,					// 硬链接数
               getpwuid(stat_buf.st_uid)->pw_name,	// 拥有者名
               getgrgid(stat_buf.st_gid)->gr_name,	// 拥有者组名
               stat_buf.st_size,					// 文件大小
               time_str,							// 最后修改时间字符串
               pdirent->d_name);					// 文件名
    }

    // 关闭目录
    closedir(dirp);
    return 0;
}
